package lib.rpc;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import lib.ArgumentValidator;
import lib.Command;
import lib.FileIO;
import lib.Utility;
import lib.logging.ILogger;
import lib.messaging.NetworkAddress;
import lib.paxos.AcceptMessage;
import lib.paxos.AckMessage;
import lib.paxos.DecideMessage;
import lib.paxos.IAcceptorState;
import lib.paxos.PaxosException;
import lib.paxos.PrepareMessage;
import lib.paxos.RoundInfo;
import lib.paxos.SyncMessage;

/**
 * RPC methods invoke implementation on server side
 * @implements {@link IRPCMethods}
 * @author abhip
 *
 */
public class ServerRPCMethods implements IRPCMethods
{
    private IAcceptorState acceptorState;
    private ILogger logger;
    private NetworkAddress serverAddress;
    private File serverRootDirectory;

    public ServerRPCMethods(
            NetworkAddress serverAddress,
            File serverRootDirectory,
            IAcceptorState acceptorState,
            ILogger logger)
    {
        ArgumentValidator.IsNotNull("serverAddress", serverAddress);
        ArgumentValidator.IsNotNull("serverRootDirectory", serverRootDirectory);
        ArgumentValidator.IsNotNull("acceptorState", acceptorState);
        ArgumentValidator.IsNotNull("logger", logger);

        this.serverAddress = serverAddress;
        this.serverRootDirectory = serverRootDirectory;
        this.acceptorState = acceptorState;
        this.logger = logger;
    }

    @Override
    public AckMessage Accept(
            NetworkAddress clientAddress,
            NetworkAddress serverAddress,
            AcceptMessage acceptMsg) throws ClassNotFoundException, IOException, PaxosException
    {
        ArgumentValidator.IsNotNull("clientAddress", clientAddress);
        ArgumentValidator.IsNotNull("serverAddress", serverAddress);
        ArgumentValidator.IsNotNull("acceptMsg", acceptMsg);

        if (!IsProposerPartOfEpoch(clientAddress))
        {
            logger.LogError(
                    "Ignoring accept request from a proposer which is not part of current epoch! Sending this feedback. " +
                        "Proposer:%s, Current epoch:%s",
                    clientAddress,
                    Utility.FlattenListToString(this.acceptorState.GetOtherServerAddresses()));

            return new AckMessage(
                    this.serverAddress,
                    acceptorState.GetTotalNumberOfCommands(),
                    acceptorState.HighestKnownSeqID(),
                    acceptorState.AcceptedMessage(),
                    new ArrayList<RoundInfo>(),
                    false);
        }

        int proposerRoundID = acceptMsg.RoundID();

        if (proposerRoundID < acceptorState.CurrentRoundID())
        {
            List<RoundInfo> missingRoundInfos = GetMissingRoundInfos(proposerRoundID);
            return new AckMessage(
                    this.serverAddress,
                    acceptorState.CurrentRoundID(),
                    acceptorState.HighestKnownSeqID(),
                    acceptorState.AcceptedMessage(),
                    missingRoundInfos,
                    true);
        }

        if (proposerRoundID == acceptorState.CurrentRoundID())
        {
            if (acceptorState.HighestKnownSeqID() == null)
            {
                logger.LogError(
                        "Got accept request for current round, " +
                            "but haven't seen any previous prepare message. " +
                            "Still going to accept it. " +
                            "Proposer:%s, current acceptor:%s, currentRoundID:%d",
                        clientAddress,
                        this.serverAddress,
                        this.acceptorState.CurrentRoundID());

                acceptorState.UpdateAcceptorState(
                        acceptMsg.RoundID(),
                        acceptMsg.SequenceID(),
                        acceptMsg,
                        new ArrayList<RoundInfo>());
            }
            else if (acceptMsg.SequenceID().IsGreaterThanOrEqualTo(acceptorState.HighestKnownSeqID()))
            {
                logger.LogInfo(
                        "Got accept request for current round." +
                            "Proposer:%s, current acceptor:%s, currentRoundID:%d, acceptMsg:%s",
                        clientAddress,
                        this.serverAddress,
                        this.acceptorState.CurrentRoundID(),
                        acceptMsg.toString());

                acceptorState.UpdateAcceptorState(
                        acceptMsg.RoundID(),
                        acceptorState.HighestKnownSeqID(),
                        acceptMsg,
                        new ArrayList<RoundInfo>());
            }
        }

        return new AckMessage(
                this.serverAddress,
                acceptorState.CurrentRoundID(),
                acceptorState.HighestKnownSeqID(),
                acceptorState.AcceptedMessage(),
                new ArrayList<RoundInfo>(),
                true);
    }

    /**
     * Server side implementation of AppendLineToFile RPC
     * @param clientAddress
     * @param expectedServerAddress
     * @param fileName
     * @param data
     * @throws IOException
     */
    @Override
    public void AppendLineToFile(
            NetworkAddress clientAddress,
            NetworkAddress expectedServerAddress,
            int roundID,
            String fileName,
            String data) throws IOException
    {
        ArgumentValidator.IsNotNull("clientAddress", clientAddress);
        ArgumentValidator.IsNotNull("expectedServerAddress", expectedServerAddress);
        ArgumentValidator.IsNotNullOrEmpty("fileName", fileName);
        ArgumentValidator.IsGreaterThan("roundID", roundID, 0);
        // appending empty string is supported, hence do only null check on data
        ArgumentValidator.IsNotNull("data", data);

        File serverDir = Utility.GetServerDirectory(this.serverRootDirectory, this.serverAddress);
        File file = new File(serverDir, fileName);
        FileIO.AppendLineToFile(file, data);
    }

    /**
     * Server side implementation of CreateFile RPC
     * @param clientAddress
     * @param expectedServerAddress
     * @param fileName
     * @throws IOException
     */
    @Override
    public void CreateFile(
            NetworkAddress clientAddress,
            NetworkAddress expectedServerAddress,
            int roundID,
            String fileName)
                    throws IOException
    {
        ArgumentValidator.IsNotNull("clientAddress", clientAddress);
        ArgumentValidator.IsNotNull("expectedServerAddress", expectedServerAddress);
        ArgumentValidator.IsGreaterThan("roundID", roundID, 0);
        ArgumentValidator.IsNotNullOrEmpty("fileName", fileName);

        File serverDir = Utility.GetServerDirectory(this.serverRootDirectory, this.serverAddress);
        File file = new File(serverDir, fileName);
        FileIO.CreateFile(file);
    }

    @Override
    public AckMessage Decide(
            NetworkAddress clientAddress,
            NetworkAddress serverAddress,
            DecideMessage decideMsg)
                    throws ClassNotFoundException, IOException, PaxosException
    {
        ArgumentValidator.IsNotNull("clientAddress", clientAddress);
        ArgumentValidator.IsNotNull("serverAddress", serverAddress);
        ArgumentValidator.IsNotNull("decideMsg", decideMsg);

        if (!IsProposerPartOfEpoch(clientAddress))
        {
            logger.LogError(
                    "Ignoring decide request from a proposer which is not part of current epoch! Sending this feedback. " +
                        "Proposer:%s, Current epoch:%s",
                    clientAddress,
                    Utility.FlattenListToString(this.acceptorState.GetOtherServerAddresses()));

            return new AckMessage(
                    this.serverAddress,
                    acceptorState.GetTotalNumberOfCommands(),
                    acceptorState.HighestKnownSeqID(),
                    acceptorState.AcceptedMessage(),
                    new ArrayList<RoundInfo>(),
                    false);
        }

        int proposerRoundID = decideMsg.RoundID();

        if (proposerRoundID < acceptorState.CurrentRoundID())
        {
            List<RoundInfo> missingRoundInfos = GetMissingRoundInfos(proposerRoundID);
            return new AckMessage(
                    this.serverAddress,
                    acceptorState.CurrentRoundID(),
                    acceptorState.HighestKnownSeqID(),
                    acceptorState.AcceptedMessage(),
                    missingRoundInfos,
                    true);
        }

        if (proposerRoundID == acceptorState.CurrentRoundID())
        {
            if (acceptorState.IsCommandDecidedForRound(proposerRoundID))
            {
                logger.LogError(
                        "Received decide request for already decided round. " +
                        "Ignoring and sending back state. currentRoundID:%d, proposerRoundID:%d.",
                        acceptorState.CurrentRoundID(),
                        proposerRoundID);

                return new AckMessage(
                        this.serverAddress,
                        acceptorState.CurrentRoundID(),
                        acceptorState.HighestKnownSeqID(),
                        acceptorState.AcceptedMessage(),
                        new ArrayList<RoundInfo>(),
                        true);
            }

            if (acceptorState.HighestKnownSeqID() == null)
            {
                logger.LogError(
                        "Got decide request for current round, " +
                            "but haven't seen any previous prepare message. " +
                            "Still going to decide upon it. " +
                            "Proposer:%s, current acceptor:%s, currentRoundID:%d",
                        clientAddress,
                        this.serverAddress,
                        this.acceptorState.CurrentRoundID());

                ExecuteCommandLocally(clientAddress, decideMsg.Command());

                List<RoundInfo> roundInfosToAppend = new ArrayList<RoundInfo>();
                roundInfosToAppend.add(new RoundInfo(decideMsg.RoundID(), decideMsg.Command()));

                acceptorState.UpdateAcceptorState(
                        decideMsg.RoundID(),
                        decideMsg.SequenceID(),
                        new AcceptMessage(
                                decideMsg.RoundID(),
                                decideMsg.SequenceID(),
                                decideMsg.Command()),
                        roundInfosToAppend);
            }
            else if (decideMsg.SequenceID().IsGreaterThanOrEqualTo(acceptorState.HighestKnownSeqID()))
            {
                if (acceptorState.AcceptedMessage() == null)
                {
                    logger.LogError(
                            "Got decide request for current round, " +
                                "but haven't accepted any previous message. " +
                                "Still going to decide upon it. " +
                                "Proposer:%s, current acceptor:%s, currentRoundID:%d",
                            clientAddress,
                            this.serverAddress,
                            this.acceptorState.CurrentRoundID());
                }
                else
                {
                    logger.LogInfo(
                            "Got decide request for current round." +
                                "Proposer:%s, current acceptor:%s, currentRoundID:%d, decideMsg:%s",
                            clientAddress,
                            this.serverAddress,
                            this.acceptorState.CurrentRoundID(),
                            decideMsg.toString());
                }

                ExecuteCommandLocally(clientAddress, decideMsg.Command());

                List<RoundInfo> roundInfosToAppend = new ArrayList<RoundInfo>();
                roundInfosToAppend.add(new RoundInfo(decideMsg.RoundID(), decideMsg.Command()));

                acceptorState.UpdateAcceptorState(
                        decideMsg.RoundID(),
                        acceptorState.HighestKnownSeqID(),
                        new AcceptMessage(
                                decideMsg.RoundID(),
                                decideMsg.SequenceID(),
                                decideMsg.Command()),
                        roundInfosToAppend);
            }
        }

        return new AckMessage(
                this.serverAddress,
                acceptorState.CurrentRoundID(),
                acceptorState.HighestKnownSeqID(),
                acceptorState.AcceptedMessage(),
                new ArrayList<RoundInfo>(),
                true);
    }

    private void ExecuteCommandLocally(NetworkAddress clientAddress, Command command)
    {
        try
        {
            if (command.CommandName().equalsIgnoreCase(IRPCMethods.CreateFileMethodName))
            {
                Object args[] = command.CommandArgs();
                int roundID = Integer.parseInt(args[0].toString());
                String fileName = (String) args[1];
                this.CreateFile(clientAddress, this.serverAddress, roundID, fileName);
                return;
            }

            if (command.CommandName().equalsIgnoreCase(IRPCMethods.AppendLineToFileMethodName))
            {
                Object args[] = command.CommandArgs();
                int roundID = Integer.parseInt(args[0].toString());
                String fileName = (String) args[1];
                String data = (String) args[2];
                this.AppendLineToFile(clientAddress, this.serverAddress, roundID, fileName, data);
                return;
            }

            if (command.CommandName().equalsIgnoreCase(IRPCMethods.GetLineFromFileMethodName))
            {
                Object args[] = command.CommandArgs();
                int roundID = Integer.parseInt(args[0].toString());
                String fileName = (String) args[1];
                int lineNumber = (Integer) args[2];
                this.GetLineFromFile(clientAddress, this.serverAddress, roundID, fileName, lineNumber);
                return;
            }

            if (command.CommandName().equalsIgnoreCase(IRPCMethods.JoinMethodName))
            {
                Object args[] = command.CommandArgs();
                int roundID = Integer.parseInt(args[0].toString());
                NetworkAddress newServerAddress = (NetworkAddress) args[1];
                this.Join(clientAddress, this.serverAddress, roundID, newServerAddress);
                return;
            }

            if (command.CommandName().equalsIgnoreCase(IRPCMethods.ReconfigureMethodName))
            {
                Object args[] = command.CommandArgs();
                int roundID = Integer.parseInt(args[0].toString());

                @SuppressWarnings("unchecked")
                List<NetworkAddress> newServers = (List<NetworkAddress>) args[1];

                this.Reconfigure(this.serverAddress, this.serverAddress, roundID, newServers);
                return;
            }

            logger.LogError(
                    "Unknown command tried to be executed locally. command:%s",
                    command.toString());
        }
        catch (IOException e)
        {
            logger.LogException(e);
        }
    }

    /**
     * Server side implementation of GetLineFromFile RPC
     * @param clientAddress
     * @param expectedServerAddress
     * @param fileName
     * @param lineNumber
     * @return line read
     * @throws IOException
     */
    @Override
    public String GetLineFromFile(
            NetworkAddress clientAddress,
            NetworkAddress expectedServerAddress,
            int roundID,
            String fileName,
            int lineNumber) throws IOException
    {
        ArgumentValidator.IsNotNull("clientName", clientAddress);
        ArgumentValidator.IsNotNull("expectedServerName", expectedServerAddress);
        ArgumentValidator.IsGreaterThan("roundID", roundID, 0);
        ArgumentValidator.IsNotNullOrEmpty("fileName", fileName);
        ArgumentValidator.IsGreaterThan("lineNumber", lineNumber, 0);

        File serverDir = Utility.GetServerDirectory(this.serverRootDirectory, this.serverAddress);
        File file = new File(serverDir, fileName);
        return FileIO.GetLineFromFile(file, lineNumber);
    }

    private List<RoundInfo> GetMissingRoundInfos(int proposerRoundID)
    {
        ArgumentValidator.IsBetweenBothInclusive(
                "proposerRoundID",
                proposerRoundID,
                1,
                acceptorState.GetTotalNumberOfCommands());

        List<RoundInfo> missingRoundInfos = new ArrayList<RoundInfo>();
        for (int i = proposerRoundID; i <= acceptorState.GetTotalNumberOfCommands(); ++i)
        {
            try
            {
                missingRoundInfos.add(acceptorState.GetRoundInfo(i));
            }
            catch (PaxosException e)
            {
                logger.LogException(e);
                continue;
            }
        }

        if (missingRoundInfos.size() > 0)
        {
            return missingRoundInfos;
        }

        return null;
    }

    private boolean IsProposerPartOfEpoch(NetworkAddress proposerAddress)
    {
        for (int i = 0; i < acceptorState.GetOtherServerAddresses().size(); ++i)
        {
            if (acceptorState.GetOtherServerAddresses().get(i).equals(proposerAddress))
            {
                return true;
            }
        }

        return false;
    }

    @Override
    public List<NetworkAddress> Join(
            NetworkAddress clientAddress,
            NetworkAddress serverAddress,
            int roundID,
            NetworkAddress newServerAddress)
    {
        ArgumentValidator.IsNotNull("clientAddress", clientAddress);
        ArgumentValidator.IsNotNull("serverAddress", serverAddress);
        ArgumentValidator.IsGreaterThan("roundID", roundID, 0);
        ArgumentValidator.IsNotNull("newServerAddress", newServerAddress);

        acceptorState.AddServerToListOfKnownServers(newServerAddress);

        List<NetworkAddress> allServers = new ArrayList<NetworkAddress>(acceptorState.GetOtherServerAddresses());
        allServers.add(this.serverAddress);

        return allServers;
    }

    @Override
    public AckMessage Prepare(
            NetworkAddress clientAddress,
            NetworkAddress serverAddress,
            PrepareMessage prepareMsg) throws PaxosException
    {
        ArgumentValidator.IsNotNull("clientAddress", clientAddress);
        ArgumentValidator.IsNotNull("serverAddress", serverAddress);
        ArgumentValidator.IsNotNull("prepareMsg", prepareMsg);

        if (!IsProposerPartOfEpoch(clientAddress))
        {
            logger.LogError(
                    "Ignoring prepare request from a proposer which is not part of current epoch! Sending this feedback. " +
                        "Proposer:%s, Current epoch:%s",
                    clientAddress,
                    Utility.FlattenListToString(this.acceptorState.GetOtherServerAddresses()));

            return new AckMessage(
                    this.serverAddress,
                    acceptorState.GetTotalNumberOfCommands(),
                    acceptorState.HighestKnownSeqID(),
                    acceptorState.AcceptedMessage(),
                    new ArrayList<RoundInfo>(),
                    false);
        }

        int proposerRoundID = prepareMsg.RoundID();

        if (proposerRoundID < acceptorState.CurrentRoundID())
        {
            List<RoundInfo> missingRoundInfos = GetMissingRoundInfos(proposerRoundID);
            return new AckMessage(
                    this.serverAddress,
                    acceptorState.CurrentRoundID(),
                    acceptorState.HighestKnownSeqID(),
                    acceptorState.AcceptedMessage(),
                    missingRoundInfos,
                    true);
        }

        if (proposerRoundID == acceptorState.CurrentRoundID())
        {
            if ((acceptorState.HighestKnownSeqID() == null) ||
                    (prepareMsg.SequenceID().IsGreaterThanOrEqualTo(acceptorState.HighestKnownSeqID())))
            {
                logger.LogInfo(
                        "Received prepare for current round" +
                            "Proposer:%s, current acceptor:%s, currentRoundID:%d",
                        clientAddress,
                        this.serverAddress,
                        acceptorState.CurrentRoundID(),
                        proposerRoundID);

                acceptorState.UpdateAcceptorState(
                        prepareMsg.RoundID(),
                        prepareMsg.SequenceID(),
                        acceptorState.AcceptedMessage(),
                        new ArrayList<RoundInfo>());
            }

            return new AckMessage(
                    this.serverAddress,
                    acceptorState.CurrentRoundID(),
                    acceptorState.HighestKnownSeqID(),
                    acceptorState.AcceptedMessage(),
                    new ArrayList<RoundInfo>(),
                    true);
        }

        if (proposerRoundID == acceptorState.CurrentRoundID() + 1)
        {
            logger.LogInfo(
                    "Beginning new round. " +
                        "Proposer:%s, current acceptor:%s, currentRoundID:%d, new roundID:%d",
                    clientAddress,
                    this.serverAddress,
                    acceptorState.CurrentRoundID(),
                    proposerRoundID);

            acceptorState.UpdateAcceptorState(
                    prepareMsg.RoundID(),
                    prepareMsg.SequenceID(),
                    null,
                    new ArrayList<RoundInfo>());

            return new AckMessage(
                    this.serverAddress,
                    acceptorState.CurrentRoundID(),
                    acceptorState.HighestKnownSeqID(),
                    acceptorState.AcceptedMessage(),
                    new ArrayList<RoundInfo>(),
                    true);
        }

        logger.LogError(
                "Got prepare request with large roundID. " +
                "Probably current server missed some rounds. Sending feedback to proposer" +
                "prepare msg roundID:%d, current roundID:%d, current server address:%s",
                prepareMsg.RoundID(),
                acceptorState.CurrentRoundID(),
                this.serverAddress);

        return new AckMessage(
                this.serverAddress,
                acceptorState.GetTotalNumberOfCommands(),
                acceptorState.HighestKnownSeqID(),
                acceptorState.AcceptedMessage(),
                new ArrayList<RoundInfo>(),
                true);
    }

    @Override
    public void Reconfigure(
            NetworkAddress clientAddress,
            NetworkAddress serverAddress,
            int roundID,
            List<NetworkAddress> newServerAddresses)
    {
        ArgumentValidator.IsNotNull("clientAddress", clientAddress);
        ArgumentValidator.IsNotNull("serverAddress", serverAddress);
        ArgumentValidator.IsGreaterThan("roundID", roundID, 0);
        ArgumentValidator.IsNotNull("newServerSet", newServerAddresses);

        logger.LogInfo(
                "Reconfiguring paxos group. New set of servers: %s",
                Utility.FlattenListToString(newServerAddresses));

        UpdateOtherServerAddresses(newServerAddresses);
    }

    @Override
    public AckMessage Sync(
            NetworkAddress clientAddress,
            NetworkAddress serverAddress,
            SyncMessage syncMsg)
                    throws ClassNotFoundException, IOException, PaxosException
    {
        ArgumentValidator.IsNotNull("clientAddress", clientAddress);
        ArgumentValidator.IsNotNull("serverAddress", serverAddress);
        ArgumentValidator.IsNotNull("syncMsg", syncMsg);

        if (!IsProposerPartOfEpoch(clientAddress))
        {
            logger.LogError(
                    "Ignoring sync request from a proposer which is not part of current epoch! Sending this feedback. " +
                        "Proposer:%s, Current epoch:%s",
                    clientAddress,
                    Utility.FlattenListToString(this.acceptorState.GetOtherServerAddresses()));

            return new AckMessage(
                    this.serverAddress,
                    acceptorState.GetTotalNumberOfCommands(),
                    acceptorState.HighestKnownSeqID(),
                    acceptorState.AcceptedMessage(),
                    new ArrayList<RoundInfo>(),
                    false);
        }

        int proposerRoundID = syncMsg.RoundID();

        if (proposerRoundID < acceptorState.CurrentRoundID())
        {
            List<RoundInfo> missingRoundInfos = GetMissingRoundInfos(proposerRoundID);
            return new AckMessage(
                    this.serverAddress,
                    acceptorState.CurrentRoundID(),
                    acceptorState.HighestKnownSeqID(),
                    acceptorState.AcceptedMessage(),
                    missingRoundInfos,
                    true);
        }

        if (proposerRoundID == acceptorState.CurrentRoundID())
        {
            logger.LogError(
                    "Ignoring sync packet bcoz proposerRoundID==currentRoundID=%d",
                    proposerRoundID);

            return new AckMessage(
                    this.serverAddress,
                    acceptorState.CurrentRoundID(),
                    acceptorState.HighestKnownSeqID(),
                    acceptorState.AcceptedMessage(),
                    new ArrayList<RoundInfo>(),
                    true);
        }

        if (syncMsg.MissingRoundInfos() == null ||
                syncMsg.MissingRoundInfos().size() == 0)
        {
            logger.LogError(
                    "Sync message does not have missingRoundInfo! Proposer:%s, syncMessage:%s",
                    clientAddress,
                    syncMsg.toString());

            return new AckMessage(
                    this.serverAddress,
                    acceptorState.CurrentRoundID(),
                    acceptorState.HighestKnownSeqID(),
                    acceptorState.AcceptedMessage(),
                    new ArrayList<RoundInfo>(),
                    true);
        }

        int missedCommandsCount = syncMsg.MissingRoundInfos().size();
        for (int i = 0; i < missedCommandsCount; ++i)
        {
            RoundInfo missedRound = syncMsg.MissingRoundInfos().get(i);

            logger.LogInfo(
                    "Executing missed command. " +
                    "Proposer:%s, Current acceptor:%s, Missing roundID:%d, missedCommand:%s",
                    clientAddress,
                    this.serverAddress,
                    missedRound.RoundID(),
                    missedRound.Command());

            ExecuteCommandLocally(clientAddress, missedRound.Command());
        }

        RoundInfo lastMissedRoundInfo = syncMsg.MissingRoundInfos().get(missedCommandsCount - 1);
        acceptorState.UpdateAcceptorState(
                syncMsg.RoundID(),
                syncMsg.SequenceID(),
                new AcceptMessage(
                        lastMissedRoundInfo.RoundID(),
                        syncMsg.SequenceID(),
                        lastMissedRoundInfo.Command()),
                syncMsg.MissingRoundInfos());

        return new AckMessage(
                this.serverAddress,
                acceptorState.CurrentRoundID(),
                acceptorState.HighestKnownSeqID(),
                acceptorState.AcceptedMessage(),
                new ArrayList<RoundInfo>(),
                true);
    }

    private void UpdateOtherServerAddresses(List<NetworkAddress> newServerAddresses)
    {
        List<NetworkAddress> otherServers = new ArrayList<NetworkAddress>();

        for (int i = 0; i < newServerAddresses.size(); ++i)
        {
            if (newServerAddresses.get(i).equals(this.serverAddress))
            {
                continue;
            }

            otherServers.add(newServerAddresses.get(i));
        }

        if (otherServers.size() == 0)
        {
            logger.LogError("Ignoring attempt to set OtherserverAddresses to empty.");
            return;
        }

        acceptorState.SetOtherServerAddresses(otherServers);
    }
}
